const { Op } = require("sequelize");

class BaseMapper {
    constructor() {

    }

    async getList(params = {}, is_dict=true) {
        let options = this.listQuerySetting(params)
        this.handleSearch(params, options)
        if(is_dict) {
            return this.toDict(await this.model.findAll(options))
        }
        return await this.model.findAll(options)
    }


    listQuerySetting(params = {}) {
        let where = {}
            , attributes = null
            ,paranoid = false
            , order = [];
        if(!params['recycle']){
            paranoid = true
        }else{
            where['deleted_at'] = {
                [Op.not]:null
            }
        }
        if(params['select']){
            attributes = params['select'].split(',')
        }

        if(params['orderBy']){
            if (Array.isArray(params['orderBy'])) {
                for (let key in params['orderBy']){
                    let val = params['orderBy'][key]
                    order.append([val, params['orderType'][key]?.toUpperCase() || 'ASC'])
                }
            } else {
                order.append([params['orderBy'], params['orderType']?.toUpperCase() || 'ASC'])
            }
        }
        return {where, attributes, order,paranoid}

    }

    async getPageList(params, pageName = 'page') {
        let options = this.listQuerySetting(params)
        let items = []
        this.handleSearch(params, options)
        let pageInfo = await this.setPaginate(params, options)
        if(pageInfo.total > 0){
            items = this.toDict(await this.model.findAll(options))
        }
        return {items, pageInfo}
    }



    toDict(data){
        if(data instanceof this.model){
            return data.get()
        }
        if(Array.isArray(data)){
            let dataList = []
            for(let key in data){
                dataList.push(data[key].get())
            }
            return dataList
        }
        return null
    }


    async setPaginate(params, options){
        let page = parseInt(params['page']) || 1
        let pageSize = parseInt(params['pageSize']) || 15
        options['offset'] = (page - 1) * pageSize
        options['limit'] = pageSize
        let total = await this.model.count(options)
        let totalPage = Math.ceil(total/pageSize)

        return  {
            total : total,
            currentPage:page,
            totalPage: totalPage
        }

    }


    handleSearch(params, options){
        //子类搜索重写
        if(params['created_at'] && params['created_at'].length === 2){
            options.where['created_at']={
                [Op.gte]: new Date(params['created_at'][0]),
                [Op.lte]: new Date(params['created_at'][1])
            }
        }
    }

    async save(data, where = null){
        if(where === null && this.model.primaryKeyAttribute in data){
                where = {
                    [this.model.primaryKeyAttribute]: data[this.model.primaryKeyAttribute]
                }
        }
        let item = null
        if(where){
            item = await this.model.findOne({where: where})
        }

        if(item === null){
            item = await this.model.create(data)
        }else{
            item.update(data)
        }
        return item
    }

    async create(data, options= {}){
        return this.model.create(data, options);
    }

    async read(id, column = ['*']) {
        return await this.model.findByPk(id)
    }

    async find(where) {
        return await this.model.findOne(where)
    }
    async count(where){
        return await this.model.count({where})
    }
    async delete(data, force = false){
        for(let i in data['ids']){
            let id = data['ids'][i]
             await  this.model.destroy({
                 where:{
                     [this.model.primaryKeyAttribute]:id
                 },
                 force: force
             })
        }

    }

    /**
     * 恢复
     * @param data
     * @returns {Promise<void>}
     */
    async recovery(data){
        for(let i in data['ids']){
            let id = data['ids'][i]
            await  this.model.restore({
                where:{
                    [this.model.primaryKeyAttribute]:id
                }
            })
        }
    }


}

module.exports = BaseMapper